﻿using System;
using System.IO;
using System.Collections.Generic;

namespace Game.Lib.CSG
{
    public class Ellipse : Shape2D
    {
        public override List<Vector> CriticalPoints
        {
            get
            {
                List<Vector> ret = new List<Vector>(5);
                ret.Add(Pos);
                ret.Add(Pos + Vector2.FromPolar(Size.X * .5f, Rot));
                ret.Add(Pos + Vector2.FromPolar(Size.X * -.5f, Rot + Utils.PI));
                ret.Add(Pos + Vector2.FromPolar(Size.X * .5f, Rot + Utils.PI_BY_TWO));
                ret.Add(Pos + Vector2.FromPolar(Size.X * -.5f, Rot + Utils.PI + Utils.PI_BY_TWO));
                return ret;
            }
        }
        public override float Area
        {
            get { return (float)(Math.PI * 0.25 * Size.X * Size.Y); }
        }

        public override float Perimeter
        {
            get
            {
                //Approximation
                double a = Size.X * 0.5;
                double b = Size.Y * 0.5;
                double del = (a - b) / (a + b);
                del *= 3 * del;
                double temp = 1 + del / (10.0 + Math.Sqrt(4.0 - del));
                return (float)(Math.PI * (a + b) * temp);
            }
        }

        public bool Circle{ get { return Size.X == Size.Y; } }

        public Ellipse()
        {
            Pos = Size = Vector2.Zero;
            Rot = 0f;
        }

        public Ellipse(Vector2 pos, float r)
        {
            Pos = pos;
            Size = new Vector2(r * 2f);
        }

        public Ellipse(Vector2 pos, Vector2 size)
        {
            Pos = pos;
            Size = size;
            Rot = 0f;
        }

        public Ellipse(Vector2 pos, Vector2 size, float rot)
            : this(pos, size)
        {
            Rot = rot;
        }

        public override Rectangle GetBoundingRectangle()
        {
            return new Rectangle(Pos, Size);
        }

        public override Ellipse GetBoundingCircle()
        {
            if (Circle) return this;
            return new Ellipse(Pos, Utils.Max(Size.X, Size.Y) * .5f);
        }

        public override bool Inside(Vector2 pos)
        {
            float r = (pos - Pos).Magnitude();
            float theta = Vector2.RotationBetween(Vector2.XAxis, pos - Pos);
            Vector2 p = Vector2.FromPolar(r, theta - Rot);
            return ((p.X * p.X) / (Size.X * Size.X)) + ((p.Y * p.Y) / (Size.Y * Size.Y)) < 4f;
        }

        public override void Serialize(Stream s)
        {
            Pos.Serialize(s);
            Size.Serialize(s);
            s.Write(BitConverter.GetBytes(Rot), 0, 4);
        }

        public override void Deserialize(Stream s)
        {
            Pos.Deserialize(s);
            Size.Deserialize(s);
            byte[] buf = new byte[4];
            if (s.Read(buf, 0, 4) != 4) throw new EndOfStreamException();
            Rot = BitConverter.ToSingle(buf, 0);
        }
    }
}
